﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace APNS.NET
{
    public class ApnsConnectionPool
    {

        private readonly Stack<IApnsConnection> _connections = new Stack<IApnsConnection>();
        private readonly Func<IApnsConnection> _connectionFactory;

        public ApnsConnectionPool(string hostname, int port, X509Certificate apnCertificate)
        {
            if (apnCertificate==null)
                throw new ArgumentNullException("apnCertificate");
            this._connectionFactory = () => new ApnsConnection(hostname, port, apnCertificate);              
        }

        public ApnsConnectionPool(Func<IApnsConnection> connectionFactory)
        {
            if (connectionFactory==null)
                throw new ArgumentNullException("connectionFactory");
            this._connectionFactory = connectionFactory;
        }

        // Get a connection from the pool
        public IApnsConnection GetConnection()
        {
            IApnsConnection result;
            lock(_connections)
            {
                if(_connections.Count==0)
                {
                    // If no available connections then create one
                    result = _connectionFactory();
                }
                else
                {
                    // If a connection is available then return one from the pool
                    result = _connections.Pop();
                }
            }
            return result;
        }

        // Release a connection back into the pool
        public void ReleaseConnection(IApnsConnection connection, bool errorState)
        {
            if (connection==null)
                throw new ArgumentNullException("connection");

            if (errorState || !connection.Connected)
            {                
                // If we can't use the connection any more then close the connection and
                // don't add it back into the pool
                connection.Close();
            }
            else
            {
                lock (_connections)
                {
                    _connections.Push(connection);
                }  
            }
            
        }

    }
}
